//@author A0105536L
package Logic;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.joestelmach.natty.DateGroup;
import com.joestelmach.natty.Parser;

import Object.DSException;
import Object.DSQuery;

/**
 * Class DSQueryFactory. This class is to create DSQuery for searching command.
 * 
 * 
 * 
 */
public class DSQueryFactory {
	/**
	 * This method is to create a DSQuery.
	 * 
	 * @param command
	 *            String that user enters for search command
	 * @return A complete DSQuery
	 * @throws DSException
	 */
	public static DSQuery createQuery(String command) throws DSException {
		DSQuery query = new DSQuery();

		// Using natty package
		Parser nattyParser = new Parser();
		List<DateGroup> enddate = new ArrayList<DateGroup>();
		List<DateGroup> startdate = new ArrayList<DateGroup>();
		int tag_num;
		if (!command.endsWith("tag")) {
			tag_num = countTag(command);
		} else {
			tag_num = 0;
		}
		int tag = 1;
		boolean from_and_to = has_From_and_To(command);
		String[] searchArray = splitCommandStrings(command);

		for (int i = 0; i < searchArray.length; i++) {
			searchArray[i].trim();
			if (searchArray[i].equalsIgnoreCase("after")) {
				String parseNatty = "";
				i++;
				while (i < searchArray.length) {
					if (searchArray[i].equalsIgnoreCase("tag")) {
						i--;
						break;
					}
					parseNatty = parseNatty + " " + searchArray[i];
					i++;
				}
				query.setDateRange(DSQuery.DATE_RANGE_AFTER_END_DATE);
				enddate = nattyParser.parse(parseNatty);
				if (!enddate.isEmpty()) {
					query.setEndDate((enddate).get(0).getDates().get(0));
				} else {
					query.setDateRange(DSQuery.DATE_RANGE_NOT_SET);
					query.addKeyWord("after");
					String[] Key = parseNatty.trim().split(" ");
					for (int j = 0; j < Key.length; j++) {
						if (!Key[j].equals(""))
							query.addKeyWord(Key[j].trim());
					}
				}
			} else if (searchArray[i].equalsIgnoreCase("before")) {
				String parseNatty = "";
				i++;
				while (i < searchArray.length) {
					if (searchArray[i].equalsIgnoreCase("tag")) {
						i--;
						break;
					}
					parseNatty = parseNatty + " " + searchArray[i];
					i++;
				}
				query.setDateRange(DSQuery.DATE_RANGE_BEFORE_END_DATE);
				enddate = nattyParser.parse(parseNatty);
				if (!enddate.isEmpty()) {
					query.setEndDate((enddate).get(0).getDates().get(0));
				} else {
					query.setDateRange(DSQuery.DATE_RANGE_NOT_SET);
					query.addKeyWord("before");
					String[] Key = parseNatty.trim().split(" ");
					for (int j = 0; j < Key.length; j++) {
						if (!Key[j].equals(""))
							query.addKeyWord(Key[j].trim());
					}
				}
			} else if (searchArray[i].equals("tag")) {
				if (tag == tag_num) {
					i++;
					while (i < searchArray.length) {
						if (!searchArray[i].equals(""))
							query.addTag(searchArray[i]);
						i++;
					}
				} else {
					tag++;
					query.addKeyWord(searchArray[i]);
				}
			} else if (searchArray[i].equalsIgnoreCase("done")) {
				query.setDoneStatus(DSQuery.STATUS_DONE);
			} else if (searchArray[i].equalsIgnoreCase("undone")) {
				query.setDoneStatus(DSQuery.STATUS_NOT_DONE);
			} else if (from_and_to && searchArray[i].equalsIgnoreCase("from")) {
				String startString = "";
				i++;
				while (!searchArray[i].equals("to")) {
					startString = startString + " " + searchArray[i];
					i++;
				}
				query.setDateRange(DSQuery.DATE_RANGE_DURING_DATE);
				startdate = nattyParser.parse(startString);

				i++;
				String endString = "";
				while (i < searchArray.length) {
					if (searchArray[i].equalsIgnoreCase("tag")) {
						i--;
						break;
					}
					endString = endString + " " + searchArray[i];
					i++;
				}
				enddate = nattyParser.parse(endString);
				if (!startdate.isEmpty() && !enddate.isEmpty()) {
					query.setStartDate((startdate).get(0).getDates().get(0));
					query.setEndDate((enddate).get(0).getDates().get(0));
				} else {
					query.setDateRange(DSQuery.DATE_RANGE_NOT_SET);
					query.addKeyWord("from");
					query.addKeyWord("to");
					String[] startKey = startString.trim().split(" ");
					String[] endKey = endString.trim().split(" ");
					for (int j = 0; j < startKey.length; j++) {
						query.addKeyWord(startKey[j].trim());
					}
					for (int j = 0; j < endKey.length; j++) {
						query.addKeyWord(endKey[j].trim());
					}
				}
			} else {
				query.addKeyWord(searchArray[i].trim().toLowerCase());
			}
		}
		return query;
	}

	/**
	 * This method is to handle overdue command.
	 * 
	 * @return Return a overdue DSQuery
	 */

	public static DSQuery overdueQuery() {
		DSQuery query = new DSQuery();
		Date Date = new Date();
		query.setDateRange(DSQuery.DATE_RANGE_BEFORE_END_DATE);
		query.setEndDate(Date);
		query.setDoneStatus(DSQuery.STATUS_NOT_DONE);
		return query;
	}

	/**
	 * This method is to count how many "tag" in the string
	 * 
	 * @param str
	 *            Given string
	 * @return Return a number.
	 */
	private static int countTag(String str) {
		return str.split("tag ").length - 1;
	}

	/**
	 * This method is to split a given string by space
	 * 
	 * @param userCommand
	 *            Given string
	 * @return Return a String array
	 */
	private static String[] splitCommandStrings(String userCommand) {
		return userCommand.trim().split(" ");
	}

	/**
	 * This method is to check a string has both "from" and "to"
	 * 
	 * @param str
	 *            A given string
	 * @return True, if the string has both "from" and "to"
	 */
	private static boolean has_From_and_To(String str) {
		return str.contains("from ") && str.contains("to ");
	}

}